/**    
 * 文件名：RentalRateService.java</br>
 *    
 * 版本信息：v1.0</br>
 * 日期：2018年4月28日</br>
 * © 2005-2017 雷技信息科技（上海）有限公司版权所有</br>
 *
 */
package com.logic.landseaserver.models.rentalrate.service;

import java.io.File;
import java.io.FileOutputStream;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.Font;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.WorkbookFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.logic.common.util.QueryUtil;
import com.logic.landseaserver.common.LandeaConstants.OffrentType;
import com.logic.landseaserver.common.config.FileConfiguration;
import com.logic.landseaserver.common.enums.ContractStatusCodeEnum;
import com.logic.landseaserver.common.exception.LandseaException;
import com.logic.landseaserver.common.exception.ResultCodes.RentalRateCode;
import com.logic.landseaserver.common.util.Arith;
import com.logic.landseaserver.common.util.DateUtil;
import com.logic.landseaserver.common.util.StringTools;
import com.logic.landseaserver.domain.Project;
import com.logic.landseaserver.models.refunddiary.service.RefundDiaryService;
import com.logic.landseaserver.models.rentalrate.bean.RentalRateContract;
import com.logic.landseaserver.models.rentalrate.bean.RentalRateResp;
import com.logic.landseaserver.models.rentalrate.bean.RentalRateRoom;
import com.logic.landseaserver.models.rentalrate.bean.RentalRateTime;
import com.logic.landseaserver.persistence.read.ContractReadMapper;
import com.logic.landseaserver.persistence.read.ProjectReadMapper;
import com.logic.landseaserver.persistence.read.RoomReadMapper;

/**
 *
 * 项目名称：system-server</br>
 * 类名称：RentalRateService</br>
 * 类描述：出租率报表</br>
 * 创建人：Aaron</br>
 * 创建时间：2018年4月28日 下午4:28:53</br>
 * 
 * @version 1.0
 *
 */
@Service
public class RentalRateService
{
    private static final Logger LOGGER = LoggerFactory.getLogger(RentalRateService.class);
    
    // 展示类型：总体
    private static final String SHOW_TYPE_TOTAL = "0";
    
    // 展示类型：详情
    private static final String SHOW_TYPE_DETIAL = "1";
    
    @Autowired
    private RoomReadMapper roomReadMapper;
    
    @Autowired
    private ProjectReadMapper projectReadMapper;
    
    @Autowired
    private ContractReadMapper contractReadMapper;
    
    @Autowired
    private FileConfiguration fileConfiguration;
    
    public List<RentalRateResp> pageList(QueryUtil queryUtil, boolean needPage)
        throws LandseaException
    {
        List<RentalRateResp> resultList = new ArrayList<RentalRateResp>();
        
        try
        {
            // 获取请求中的日期
            Map<String, Object> reqMap = queryUtil.getParams();
            String startTimeStr = (String)reqMap.get("startTime");
            String endTimeStr = (String)reqMap.get("endTime");
            
            // 精确到天
            Date startTime = DateUtil.convertDate(startTimeStr);
            Date endTime = DateUtil.convertDate(endTimeStr);
            if (null == startTime || null == endTime)
            {
                throw LandseaException.createException(RentalRateCode.E004600001);
            }
            if (startTime.getTime() > endTime.getTime())
            {
                throw LandseaException.createException(RentalRateCode.E004600002);
            }
            
            // 获取参数中的城市
            String areaCode = null;
            String areaCodeZh = null;
            // 获取参数中的项目ID
            Integer projectId = null;
            // 展示类型：0：显示总体，1：显示明细
            String showType = SHOW_TYPE_TOTAL;
            Map<String, Object> paramMap = queryUtil.getParams();
            if (MapUtils.isNotEmpty(paramMap))
            {
                areaCode = (String)paramMap.get("areaCode");
                areaCodeZh = (String)paramMap.get("areaCodeZh");
                projectId = (Integer)paramMap.get("projectId");
                showType = (String)paramMap.get("showType");
            }
            
            if (StringUtils.isEmpty(areaCode))
            {
                throw LandseaException.createException(RentalRateCode.E004600003);
            }
            
            if (!SHOW_TYPE_TOTAL.equals(showType) && !SHOW_TYPE_DETIAL.equals(showType))
            {
                showType = SHOW_TYPE_TOTAL;
            }
            
            // 查询区域下所有的门店
            // 根据该项目的城市公司查询所有正常的项目,项目为发布态、非删除态
            List<Project> projectList = projectReadMapper.getProjectByArea(areaCode);
            // 根据项目ID过滤
            if (CollectionUtils.isEmpty(projectList))
            {
                queryUtil.getPagingTool().setTotalNum(0);
                return resultList;
            }
            
            Map<Integer, List<RentalRateContract>> projectRateMap = new HashMap<Integer, List<RentalRateContract>>();
            Map<Integer, Project> projectMap = new HashMap<Integer, Project>();
            
            if (null != projectId)
            {
                Iterator<Project> iterator = projectList.iterator();
                while (iterator.hasNext())
                {
                    Project project = iterator.next();
                    if (project.getId().intValue() != projectId.intValue())
                    {
                        iterator.remove();
                        continue;
                    }
                    
                    List<RentalRateContract> list = new ArrayList<RentalRateContract>();
                    projectRateMap.put(project.getId(), list);
                    projectMap.put(project.getId(), project);
                }
            }
            else
            {
                for (Project project : projectList)
                {
                    List<RentalRateContract> list = new ArrayList<RentalRateContract>();
                    projectRateMap.put(project.getId(), list);
                    projectMap.put(project.getId(), project);
                }
            }
            
            // 计算时间段
            List<RentalRateTime> rentalRateTimeList = getAllTimes(startTime, endTime, showType);
            if (CollectionUtils.isEmpty(rentalRateTimeList))
            {
                queryUtil.getPagingTool().setTotalNum(0);
                return resultList;
            }
            
            // 查询要统计的房间总数,根据时间、城市公司、项目
            Map<String, Object> queryMap = new HashMap<String, Object>();
            queryMap.put("areaCode", areaCode);
            queryMap.put("projectId", projectId);
            queryMap.put("startTime", startTime);
            queryMap.put("endTime", endTime);
            List<RentalRateRoom> rentalRateRoomList = roomReadMapper.queryRentalRateRoom(queryMap);
            
            if (CollectionUtils.isEmpty(rentalRateRoomList))
            {
                queryUtil.getPagingTool().setTotalNum(0);
                return resultList;
            }
            
            // 查询城市公司项目下所有合同（签约中、已结束的）
            List<RentalRateContract> contractList = contractReadMapper.queryRentalRateContract(paramMap);
            if (CollectionUtils.isEmpty(contractList))
            {
                // 返回所有的平均出租率都是0
                emptyListResp(resultList, projectList, rentalRateTimeList, areaCodeZh);
                queryUtil.getPagingTool().setTotalNum(resultList.size());
                return resultList;
            }
            
            // 将房间合同信息按照门店整理
            for (RentalRateContract rateContract : contractList)
            {
                projectRateMap.get(rateContract.getProjectId()).add(rateContract);
            }
            
            // 按照门店进行处理
            resultList =
                projectRateProcess(projectMap, projectRateMap, rentalRateTimeList, rentalRateRoomList, areaCodeZh);
            
            if (needPage)
            {
                // 分页
                int startRecord = queryUtil.getPagingTool().getStart();
                int endRecord = startRecord + queryUtil.getPagingTool().getPageSize();
                
                int totalRecord = resultList.size();
                
                queryUtil.getPagingTool().setTotalNum(totalRecord);
                
                if (startRecord >= totalRecord)
                {
                    resultList.clear();
                    return resultList;
                }
                
                if (endRecord >= totalRecord)
                {
                    endRecord = totalRecord;
                }
                
                resultList = resultList.subList(startRecord, endRecord);
            }
            
            return resultList;
        }
        catch (LandseaException e)
        {
            throw e;
        }
        catch (Exception e)
        {
            LOGGER.error("pageList|查询平均出租率异常.", e);
            throw LandseaException.createException(RentalRateCode.E004600004);
        }
    }
    
    /**
     * 
     * [简要描述]：返回空的记录</br>
     * [详细描述]：</br>
     * [作者]：Aaron(2018-06-12)</br>
     *
     * @param resultList
     * @param projectList
     * @param rentalRateTimeList
     *
     */
    private void emptyListResp(List<RentalRateResp> resultList, List<Project> projectList, List<RentalRateTime> rentalRateTimeList, String areaCodeZh)
    {
        // 返回所有的平均出租率都是0
        RentalRateResp resp = null;
        for (Project project : projectList)
        {
            for (RentalRateTime rentalRateTime : rentalRateTimeList)
            {
                resp = new RentalRateResp();
                resp.setAreaCodeZh(areaCodeZh);
                resp.setProjectName(project.getPrjName());
                resp.setStartTime(rentalRateTime.getStartTime());
                resp.setEndTime(rentalRateTime.getEndTime());
                resp.setRentalRate(0.00d);
                resultList.add(resp);
            }
        }
    }
    
    /**
     * 
     * [简要描述]：获取计算促出租率的时间</br>
     * [详细描述]：</br>
     * [作者]：Aaron(2018-05-03)</br>
     *
     * @param startTime
     * @param endTime
     * @param showType
     * @return
     * @throws LandseaException
     *
     */
    private List<RentalRateTime> getAllTimes(Date startTime, Date endTime, String showType)
        throws LandseaException
    {
        List<RentalRateTime> timeList = new ArrayList<RentalRateTime>();
        
        startTime = DateUtil.dateConvertDate(startTime);
        endTime = DateUtil.dateConvertDate(endTime);
        
        // 如果是展示总体，则直接返回当前时间
        if (SHOW_TYPE_TOTAL.equals(showType))
        {
            RentalRateTime all = new RentalRateTime();
            all.setEndTime(endTime);
            all.setStartTime(startTime);
            timeList.add(all);
            
            return timeList;
        }
        
        try
        {
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(startTime);
            
            while (!calendar.getTime().after(endTime))
            {
                RentalRateTime daysTime = new RentalRateTime();
                daysTime.setStartTime(startTime);
                daysTime.setEndTime(calendar.getTime());
                timeList.add(daysTime);
                calendar.add(Calendar.DAY_OF_YEAR, 1);
            }
            
            return timeList;
        }
        catch (Exception e)
        {
            LOGGER.error("getAllTimes|查询平均出租率处理时间异常.", e);
            throw LandseaException.createException(RentalRateCode.E004600005, e);
        }
    }
    
    /**
     * 
     * [简要描述]：</br>
     * [详细描述]：</br>
     * [作者]：Aaron(2018-06-04)</br>
     *
     * @param projectMap 门店集合
     * @param projectRateMap 门店-统计合同集合
     * @param rentalRateTimeList 统计的时间段集合
     * @param rentalRateRoomList 统计的总房间集合
     * @throws LandseaException
     *
     */
    private List<RentalRateResp> projectRateProcess(Map<Integer, Project> projectMap,
        Map<Integer, List<RentalRateContract>> projectRateMap, List<RentalRateTime> rentalRateTimeList,
        List<RentalRateRoom> rentalRateRoomList, String areaCodeZh)
        throws LandseaException
    {
        List<RentalRateResp> resultList = new ArrayList<RentalRateResp>();
        Set<Entry<Integer, List<RentalRateContract>>> set = projectRateMap.entrySet();
        for (Entry<Integer, List<RentalRateContract>> entry : set)
        {
            // 获取门店
            Project project = projectMap.get(entry.getKey());
            List<RentalRateContract> rateContractList = entry.getValue();
            
            // 根据时间范围，过滤出复合要求的房间
            for (RentalRateTime rentalRateTime : rentalRateTimeList)
            {
                RentalRateResp rentalRateResp = new RentalRateResp();
                rentalRateResp.setAreaCodeZh(areaCodeZh);
                rentalRateResp.setProjectName(project.getPrjName());
                rentalRateResp.setStartTime(rentalRateTime.getStartTime());
                rentalRateResp.setEndTime(rentalRateTime.getEndTime());
                
                double rentalRate = doDay(rateContractList, rentalRateResp, rentalRateRoomList);
                rentalRateResp.setRentalRate(rentalRate);
                resultList.add(rentalRateResp);
            }
        }
        return resultList;
    }
    
    private double doDay(List<RentalRateContract> rateContractList, RentalRateResp rentalRateResp,
        List<RentalRateRoom> rentalRateRoomList)
        throws LandseaException
    {
        
        // 所有房间在该时间段内有效的出租天数总数
        int roomTotalRentDays = 0;
        
        // 只统计时间范围内的
        for (RentalRateContract rateContract : rateContractList)
        {
            Date start = null;
            Date end = null;
            // 如果是结束的合同
            if (ContractStatusCodeEnum.END.getCode().equals(rateContract.getContractStatus()))
            {
                // 判断是否是提前退房
                if (OffrentType.ADVANCE.equals(rateContract.getOffrentType()))
                {
                    // 提前退房，截止时间要取放租缴纳结束日期
                    start = rateContract.getContractInDate();
                    end = rateContract.getLastRentDateEnd();
                }
                // 换房退房，要获取换房日期
                else if (OffrentType.CHANGEROOM.equals(rateContract.getOffrentType()))
                {
                    start = rateContract.getContractInDate();
                    end = rateContract.getChangeRoomDate();
                }
                // 转房退房，要获取转房日期
                else if (OffrentType.CHANGERENT.equals(rateContract.getOffrentType()))
                {
                    start = rateContract.getContractInDate();
                    end = rateContract.getReRentDate();
                }
                else
                {
                    // 非提前退房,结束日期为实际退房日期
                    start = rateContract.getContractInDate();
                    end = rateContract.getRealOffrentDate();
                }
            }
            else
            {
                // 正在入住的合同，结束日期获取最后一期的房租缴纳截止日期
                start = rateContract.getContractInDate();
                end = rateContract.getLastRentDateEnd();
            }
            
            // 如果还是end为空，就直接获取contract的结束日期把
            if (null == end)
            {
                LOGGER.info("doDay|通过计算end仍然为空，或者合同的结束日期为end日期." + rateContract);
                end = rateContract.getContractOutDate();
            }
            
            // 只考虑两个时间段重合的天数
            List<String> overlapList =
                DateUtil.getAlphalDate(rentalRateResp.getStartTime(), rentalRateResp.getEndTime(), start, end);
            roomTotalRentDays += overlapList.size();
        }
        
        // 嫉妒总天数
        int totalDay = DateUtil.daysBetween(rentalRateResp.getStartTime(), rentalRateResp.getEndTime());
        
        // 计算概率
        double rate = Arith.div(roomTotalRentDays, rentalRateRoomList.size() * totalDay, 2);
        return Arith.mul(rate, 100);
    }
    
    public String exportExcel(QueryUtil queryUtil)
        throws LandseaException
    {
        String url = fileConfiguration.getRemote();
        String excelpath = fileConfiguration.getExcelPath();
        
        InputStream ins = null;
        Workbook workbook = null;
        try
        {
            ins = RefundDiaryService.class.getClassLoader().getResourceAsStream("平均出租率报表.xlsx");
            workbook = WorkbookFactory.create(ins);
        }
        catch (Exception e)
        {
            LOGGER.error("exportExcel|读取Excel模板失败.", e);
            throw LandseaException.createException(RentalRateCode.E004600006, e);
        }
        finally
        {
            try
            {
                if (null != ins)
                {
                    ins.close();
                }
            }
            catch (IOException e)
            {
                LOGGER.error("exportExcel|关闭读取流失败.", e);
                throw LandseaException.createException(RentalRateCode.E004600006, e);
            }
        }
        
        // 根据条件，查询所有
        List<RentalRateResp> recordList = pageList(queryUtil, false);
        
        // 获取城市，时间范围
        // 获取请求中的日期
        Map<String, Object> reqMap = queryUtil.getParams();
        String startTimeStr = (String)reqMap.get("startTime");
        String endTimeStr = (String)reqMap.get("endTime");
        String areaCodeZh = (String)reqMap.get("areaCodeZh");
        
        Sheet sheet = workbook.getSheet("平均出租率报表");
        // 生成一个样式
        CellStyle style = workbook.createCellStyle();
        // 设置这些样式
        style.setAlignment(CellStyle.ALIGN_CENTER);
        // 生成一个字体
        Font font = workbook.createFont();
        font.setFontHeightInPoints((short)14);
        font.setBoldweight(Font.BOLDWEIGHT_BOLD);
        // 把字体应用到当前的样式
        style.setFont(font);
        
        // 修改表头城市、时间
        Row firstRow = sheet.getRow(0);
        Cell cityCell = firstRow.getCell(1);
        cityCell.setCellType(Cell.CELL_TYPE_STRING);
        cityCell.setCellValue(areaCodeZh);
        Cell dateCell = firstRow.getCell(3);
        dateCell.setCellType(Cell.CELL_TYPE_STRING);
        dateCell.setCellValue(startTimeStr + " 至 " + endTimeStr);
        
        Row row;
        int startRow = 2;
        for (int i = 0; i < recordList.size(); i++)
        {
            RentalRateResp rentalRateResp = recordList.get(i);
            
            row = sheet.createRow(startRow + i);
            // 序号
            row.createCell(0).setCellValue(i + 1);
            // 城市
            row.createCell(1).setCellValue(StringTools.getStr(rentalRateResp.getAreaCodeZh()));
            // 项目名称
            row.createCell(2).setCellValue(StringTools.getStr(rentalRateResp.getProjectName()));
            // 日期范围
            row.createCell(3).setCellValue(DateUtil.convertDate(rentalRateResp.getStartTime()) + " 至 "
                + DateUtil.convertDate(rentalRateResp.getEndTime()));
            // 平均出租率
            row.createCell(4).setCellValue(rentalRateResp.getRentalRate() + "%");
        }
        
        // 下面是生成excel文件
        OutputStream fos = null;
        try
        {
            String filepath = fileConfiguration.getLocal() + File.separator + excelpath;
            File file = new File(filepath);
            // 如果文件夹不存在则创建
            if (!file.exists() && !file.isDirectory())
            {
                boolean mkdirResult = file.mkdir();
                if (!mkdirResult)
                {
                    LOGGER.error("exportExcel|创建临时文件夹失败.filepath=" + filepath);
                    throw LandseaException.createException(RentalRateCode.E004600006);
                }
            }
            
            // 删除userId开头的excel
            String fileExcelPre = "平均出租率报表 _";
            String[] files = file.list(new FilenameFilter()
            {
                @Override
                public boolean accept(File dir, String name)
                {
                    return name.startsWith(fileExcelPre) && name.endsWith(".xlsx");
                }
            });
            if (null != files)
            {
                // 获取7天前的时间戳
                Calendar calendar = Calendar.getInstance();
                calendar.add(Calendar.DAY_OF_YEAR, -7);
                calendar.set(Calendar.HOUR_OF_DAY, 0);
                calendar.set(Calendar.MINUTE, 0);
                calendar.set(Calendar.SECOND, 0);
                long currentDateLong = calendar.getTimeInMillis();
                
                // 删除修改时间一周之前的文件
                for (String f : files)
                {
                    File fileDelete = new File(filepath + File.separator + f);
                    if (currentDateLong >= fileDelete.lastModified())
                    {
                        fileDelete.delete();
                    }
                }
            }
            
            Date nowTime = new Date();
            String time = DateUtil.convertWeBankTime(nowTime);
            
            String fileName = fileExcelPre + time + ".xlsx";
            fos = new FileOutputStream(filepath + File.separator + fileName);
            workbook.write(fos);
            
            fos.flush();
            
            StringBuffer returnUrl = new StringBuffer();
            returnUrl.append(url);
            returnUrl.append(File.separator);
            returnUrl.append(excelpath);
            returnUrl.append(File.separator);
            returnUrl.append(fileName);
            return returnUrl.toString();
        }
        catch (Exception e)
        {
            LOGGER.error("exportExcel|生成平均出租率报表excel失败.", e);
            throw LandseaException.createException(RentalRateCode.E004600006);
        }
        finally
        {
            try
            {
                if (null != fos)
                {
                    fos.close();
                }
            }
            catch (IOException e)
            {
                LOGGER.error("exportExcel|生成平均出租率报表excel关闭流失败.", e);
                throw LandseaException.createException(RentalRateCode.E004600006);
            }
        }
    }
}
